const { ConcatSource } = require("webpack-sources");
const BasicEvaluatedExpression = require("webpack/lib/javascript/BasicEvaluatedExpression");

module.exports = class PlgunA {
  constructor() {}

  apply(compiler) {
    compiler.hooks.entryOption.tap("plgunA", (context, entry) => {
      console.log("entryOption");
    });

    compiler.hooks.afterPlugins.tap("plgunA", (compiler) => {
      console.log("afterPlugins");
    });

    compiler.hooks.initialize.tap("plgunA", () => {
      console.log("initialize");
    });

    compiler.hooks.beforeRun.tap("plgunA", (compiler) => {
      console.log("beforeRun");
    });

    compiler.hooks.run.tap("plgunA", (compiler) => {
      console.log("webpack 构建正在启动！");
    });

    compiler.hooks.normalModuleFactory.tap("plgunA", (factory) => {
      console.log("normalModuleFactory");

      factory.hooks.parser
        .for("javascript/auto")
        .tap("jsParserPlugin", (parser, options) => {
          parser.hooks.evaluateTypeof
            .for("myIdentifier")
            .tap("evaluateTypeof", (expr) => {
              const evaluateToString = value => {
                return function stringExpression(expr) {
                  return new BasicEvaluatedExpression().setString(value).setRange(expr.range);
                };
              }

              evaluateToString('object')

              // return new BasicEvaluatedExpression()
              //   .setString('abc')
              //   .setRange(expr.range);
            });
        });

      // factory.hooks.parser
      //   .for("javascript/auto")
      //   .tap("jsParserPlugin", (parser, options) => {
      //     parser.hooks.evaluate.for("String").tap("evaluateHook", (expr) => {
      //       console.log("---expr");
      //     });
      //   });
    });

    compiler.hooks.beforeCompile.tapAsync("plgunA", (params, callback) => {
      params["plgunA - data"] = "important stuff my plugin will use later";
      callback();
    });

    compiler.hooks.compile.tap("plgunA", (compilationParams) => {
      console.log("compile");
    });

    compiler.hooks.thisCompilation.tap(
      "plgunA",
      (compilation, compilationParams) => {
        console.log("thisCompilation");
      }
    );

    compiler.hooks.compilation.tap(
      "plgunA",
      (compilation, compilationParams) => {
        console.log("compilation");

        compilation.hooks.buildModule.tap("compilationPlugin", (module) => {
          module.useSourceMap = true;
          module.binary = true;
        });

        compilation.hooks.succeedModule.tap("compilationPlugin", (module) => {
          console.log("succeedModule");
        });

        compilation.hooks.finishModules.tapAsync(
          "compilationPlugin",
          (modules, callback) => {
            console.log("finishModules");
            callback();
          }
        );

        compilation.hooks.additionalAssets.tapAsync(
          "compilationPlugin",
          (callback) => {
            // console.log(compilation);

            callback();
          }
        );

        compilation.hooks.processAssets.tap(
          {
            name: "compilationPlugin",
            stage: compilation.constructor.PROCESS_ASSETS_STAGE_ADDITIONS, // see below for more stages
          },
          (assets) => {
            console.log("List of assets and their sizes:");
            Object.entries(assets).forEach(([pathname, source]) => {
              console.log(`— ${pathname}: ${source.size()} bytes`);
            });
          }
        );

        compilation.hooks.processAssets.tap(
          {
            name: "compilationPlugin",
            stage: compilation.constructor.PROCESS_ASSETS_STAGE_ADDITIONAL, // see below for more stages
          },
          (assets) => {
            console.log("PROCESS_ASSETS_STAGE_ADDITIONAL");
            Object.entries(assets).forEach(([pathname, source]) => {
              assets[pathname] = new ConcatSource(
                "/**Sweet Banner**/",
                "\n",
                source
              );
            });
          }
        );
      }
    );

    compiler.hooks.make.tap("plgunA", (compilation) => {
      console.log("make: compilation 结束之前执行");
    });

    compiler.hooks.afterCompile.tapAsync("plgunA", (compilation, callback) => {
      console.log("afterCompile: ");
      callback();
    });

    compiler.hooks.shouldEmit.tap("plgunA", (compilation) => {
      // 返回 true 以输出 output 结果，否则返回 false
      return true;
    });

    compiler.hooks.emit.tapAsync("plgunA", (compilation, callback) => {
      // 输出 asset 到 output 目录之前执行
      console.log("emit");
      callback();
    });

    compiler.hooks.afterEmit.tapAsync("plgunA", (compilation, callback) => {
      // 输出 asset 到 output 目录之后执行
      callback();
    });

    compiler.hooks.assetEmitted.tapAsync("plgunA", (file, info) => {
      // 在 asset 被输出时执行
      // console.log(file);
    });

    compiler.hooks.done.tapAsync("plgunA", (stats) => {
      // 在 asset 被输出时执行
      // console.log(stats.toJson())
    });
  }
};
